DEFINE(XSI_PSR_IC, (SHAREDINFO_ADDR+offsetof(vcpu_info_t, arch.interrupt_collection_enabled)));
DEFINE(XSI_PSR_I_OFS, offsetof(vcpu_info_t, arch.interrupt_delivery_enabled));
DEFINE(XSI_IIP_OFS, offsetof(vcpu_info_t, arch.iip));
+ DEFINE(XSI_IPSR, (SHAREDINFO_ADDR+offsetof(vcpu_info_t, arch.ipsr)));
DEFINE(XSI_IPSR_OFS, offsetof(vcpu_info_t, arch.ipsr));
DEFINE(XSI_IFS_OFS, offsetof(vcpu_info_t, arch.ifs));
+ DEFINE(XSI_IIM_OFS, offsetof(vcpu_info_t, arch.iim));
DEFINE(XSI_BANKNUM_OFS, offsetof(vcpu_info_t, arch.banknum));
+ DEFINE(XSI_BANK0_OFS, offsetof(vcpu_info_t, arch.bank0_regs[0]));
+ DEFINE(XSI_BANK1_OFS, offsetof(vcpu_info_t, arch.bank1_regs[0]));
DEFINE(XSI_METAPHYS_OFS, offsetof(vcpu_info_t, arch.metaphysical_mode));
+ DEFINE(XSI_PRECOVER_IFS_OFS, offsetof(vcpu_info_t, arch.precover_ifs));
DEFINE(XSI_INCOMPL_REG_OFS, offsetof(vcpu_info_t, arch.incomplete_regframe));
DEFINE(XSI_PEND_OFS, offsetof(vcpu_info_t, arch.pending_interruption));
DEFINE(XSI_RR0_OFS, offsetof(vcpu_info_t, arch.rrs[0]));
DEFINE(IA64_VCPU_META_RR0_OFFSET, offsetof (struct exec_domain, arch.metaphysical_rr0));
DEFINE(IA64_VCPU_META_SAVED_RR0_OFFSET, offsetof (struct exec_domain, arch.metaphysical_saved_rr0));
+ DEFINE(IA64_VCPU_BREAKIMM_OFFSET, offsetof (struct exec_domain, arch.breakimm));
+ DEFINE(IA64_VCPU_IVA_OFFSET, offsetof (struct exec_domain, arch.iva));
BLANK();
if (d == dom0) paddr += dom0_start;
imva = domain_mpa_to_imva(d,paddr);
- build_hypercall_bundle(imva,d->breakimm,hypercall,1);
+ build_hypercall_bundle(imva,d->arch.breakimm,hypercall,1);
}
if (d == dom0) paddr += dom0_start;
imva = domain_mpa_to_imva(d,paddr);
- build_hypercall_bundle(imva,d->breakimm,hypercall,ret);
+ build_hypercall_bundle(imva,d->arch.breakimm,hypercall,ret);
}
*/
d->xen_vastart = 0xf000000000000000;
d->xen_vaend = 0xf300000000000000;
- d->breakimm = 0x1000;
+ d->arch.breakimm = 0x1000;
// stay on kernel stack because may get interrupts!
// ia64_ret_from_clone (which b0 gets in new_thread) switches
d->xen_vastart = 0xf000000000000000;
d->xen_vaend = 0xf300000000000000;
d->shared_info_va = 0xf100000000000000;
- d->breakimm = 0x1000;
+ d->arch.breakimm = 0x1000;
+ ed->arch.breakimm = d->arch.breakimm;
// stay on kernel stack because may get interrupts!
// ia64_ret_from_clone (which b0 gets in new_thread) switches
// to user stack
// if not one of the above, give up for now and do it the slow way
br.sptk.many dispatch_break_fault ;;
+// reflect domain breaks directly to domain
+// FIXME: DOES NOT WORK YET
+// r16 == cr.isr
+// r17 == cr.iim
+// r18 == XSI_PSR_IC
+// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits)
+// r22 == IA64_KR(CURRENT)+IA64_VCPU_BREAKIMM_OFFSET
+// r31 == pr
+GLOBAL_ENTRY(fast_break_reflect)
+ mov r20=cr.ipsr;;
+ // if big-endian domain or privileged-perfmon bits set, do slow way
+ extr.u r21=r20,IA64_PSR_BE_BIT,1 ;;
+ cmp.ne p7,p0=r21,r0
+(p7) br.sptk.many dispatch_break_fault ;;
+ extr.u r21=r20,IA64_PSR_PP_BIT,1 ;;
+ cmp.ne p7,p0=r21,r0
+(p7) br.sptk.many dispatch_break_fault ;;
+ // ensure ipsr.cpl==2, ipsr.ri==0
+ // FIXME: any other psr bits need to be properly set/validated?
+ // ...see process.c: DELIVER_PSR_CLR/SET
+ extr.u r21=r20,IA64_PSR_CPL0_BIT,2;;
+ extr.u r23=r20,IA64_PSR_RI_BIT,2;;
+ dep r20=-1,r20,IA64_PSR_CPL1_BIT,1 ;;
+ dep r20=0,r20,IA64_PSR_CPL0_BIT,1 ;;
+ dep r20=0,r20,IA64_PSR_RI_BIT,2 ;;
+ mov cr.ipsr=r20;;
+ // save ipsr in shared_info, vipsr.cpl==(ipsr.cpl==3)?3:0
+ cmp.ne p7,p0=3,r21;;
+(p7) mov r21=r0
+ dep r20=r21,r20,IA64_PSR_CPL0_BIT,2 ;;
+ dep r20=r23,r20,IA64_PSR_RI_BIT,2 ;;
+ // vipsr.i=vpsr.i
+ adds r21=XSI_PSR_I_OFS-XSI_PSR_IC_OFS,r18 ;;
+ ld4 r21=[r21];;
+ dep r20=r21,r20,IA64_PSR_I_BIT,1 ;;
+ adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;;
+ // FIXME: any other vpsr bits need to be properly set/validated?
+ st8 [r21]=r20;;
+ // save iim in shared_info
+ adds r21=XSI_IIM_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r17;;
+ // save iip in shared_info
+ mov r20=cr.iip;;
+ adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r20;;
+ // save ifs in shared_info
+ adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st4 [r21]=r0 ;;
+ adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18
+ st8 [r21]=r0 ;;
+ cover ;;
+ mov r20=cr.ifs;;
+ adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r20;;
+ // vpsr.i = vpsr.ic = 0 on delivery of interruption
+ st8 [r18]=r0;;
+ // FIXME: need to save iipa and isr to be arch-compliant
+ // set iip to go to domain IVA break instruction vector
+ adds r22=IA64_VCPU_IVA_OFFSET-IA64_VCPU_BREAKIMM_OFFSET,r22;;
+ ld8 r23=[r22];;
+ movl r24=0x2c00;;
+ add r24=r24,r23;;
+ mov cr.iip=r24;;
+ // OK, now all set to go except for switch to virtual bank0
+ mov r30=r2; mov r29=r3;;
+ adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18;
+ adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;;
+ bsw.1;;
+ st8 [r2]=r16,16; st8 [r3]=r17,16 ;;
+ st8 [r2]=r18,16; st8 [r3]=r19,16 ;;
+ st8 [r2]=r20,16; st8 [r3]=r21,16 ;;
+ st8 [r2]=r22,16; st8 [r3]=r23,16 ;;
+ st8 [r2]=r24,16; st8 [r3]=r25,16 ;;
+ st8 [r2]=r26,16; st8 [r3]=r27,16 ;;
+ st8 [r2]=r28,16; st8 [r3]=r29,16 ;;
+ st8 [r2]=r30,16; st8 [r3]=r31,16 ;;
+ movl r31=XSI_IPSR;;
+ bsw.0 ;;
+ mov r2=r30; mov r3=r29;;
+ adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st4 [r20]=r0 ;;
+ mov pr=r31,-1 ;;
+ rfi
+ ;;
+
+
// ensure that, if giving up, registers at entry to fast_hyperprivop unchanged
ENTRY(hyper_rfi)
#define FAST_HYPERPRIVOP_CNT
ld8 r20=[r20];;
dep r20=0,r20,38,25;; // ensure ifs has no reserved bits set
mov cr.ifs=r20 ;;
-// TODO: increment a counter so we can count how many rfi's go the fast way
-// but where? counter must be pinned
// ipsr.cpl == (vcr.ipsr.cpl == 0) 2 : 3;
dep r21=-1,r21,IA64_PSR_CPL1_BIT,1 ;;
// vpsr.i = vcr.ipsr.i; vpsr.ic = vcr.ipsr.ic
ld8 r19=[r18]
;;
cmp.eq p7,p0=r0,r17 // is this a psuedo-cover?
-(p7) br.sptk.many dispatch_privop_fault
+(p7) br.spnt.many dispatch_privop_fault
;;
- cmp4.ne p7,p0=r0,r19
-(p7) br.sptk.many dispatch_break_fault
- // If we get to here, we have a hyperprivop
- // For now, hyperprivops are handled through the break mechanism
- // Later, they will be fast hand-coded assembly with psr.ic off
+ // if vpsr.ic is off, we have a hyperprivop
+ // A hyperprivop is hand-coded assembly with psr.ic off
// which means no calls, no use of r1-r15 and no memory accesses
// except to pinned addresses!
-#define FAST_HYPERPRIVOPS
-#ifdef FAST_HYPERPRIVOPS
- br.sptk.many fast_hyperprivop
+ cmp4.eq p7,p0=r0,r19
+(p7) br.sptk.many fast_hyperprivop
+ ;;
+ mov r22=IA64_KR(CURRENT);;
+ adds r22=IA64_VCPU_BREAKIMM_OFFSET,r22;;
+ ld4 r23=[r22];;
+ cmp4.eq p6,p7=r23,r17 // Xen-reserved breakimm?
+(p6) br.spnt.many dispatch_break_fault
+ ;;
+//#define FAST_BREAK
+#ifdef FAST_BREAK
+ br.sptk.many fast_break_reflect
#else
- br.sptk.many dispatch_break_fault
+ br.spnt.many dispatch_break_fault
#endif
;;
#endif
char *s = buf;
unsigned long total = 0;
for (i = 1; i <= HYPERPRIVOP_MAX; i++) total += slow_hyperpriv_cnt[i];
- s += sprintf(s,"Slow hyperprivops (total %d:\n",total);
+ s += sprintf(s,"Slow hyperprivops (total %d):\n",total);
for (i = 1; i <= HYPERPRIVOP_MAX; i++)
if (slow_hyperpriv_cnt[i])
s += sprintf(s,"%10d %s\n",
slow_hyperpriv_cnt[i], hyperpriv_str[i]);
total = 0;
for (i = 1; i <= HYPERPRIVOP_MAX; i++) total += fast_hyperpriv_cnt[i];
- s += sprintf(s,"Fast hyperprivops (total %d:\n",total);
+ s += sprintf(s,"Fast hyperprivops (total %d):\n",total);
for (i = 1; i <= HYPERPRIVOP_MAX; i++)
if (fast_hyperpriv_cnt[i])
s += sprintf(s,"%10d %s\n",
int n = dump_privop_counts(buf);
n += dump_hyperprivop_counts(buf + n);
+ n += dump_reflect_counts(buf + n);
#ifdef PRIVOP_ADDR_COUNT
n += dump_privop_addrs(buf + n);
#endif
#ifdef PRIVOP_ADDR_COUNT
zero_privop_addrs();
#endif
+ zero_reflect_counts();
if (len < TMPBUFLEN) return -1;
if (__copy_to_user(ubuf,buf,n)) return -1;
return n;
return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK));
}
+unsigned long slow_reflect_count[0x80] = { 0 };
+unsigned long fast_reflect_count[0x80] = { 0 };
+
+#define inc_slow_reflect_count(vec) slow_reflect_count[vec>>8]++;
+
+void zero_reflect_counts(void)
+{
+ int i;
+ for (i=0; i<0x80; i++) slow_reflect_count[i] = 0;
+ for (i=0; i<0x80; i++) fast_reflect_count[i] = 0;
+}
+
+int dump_reflect_counts(char *buf)
+{
+ int i,j,cnt;
+ char *s = buf;
+
+ s += sprintf(s,"Slow reflections by vector:\n");
+ for (i = 0, j = 0; i < 0x80; i++) {
+ if (cnt = slow_reflect_count[i]) {
+ s += sprintf(s,"0x%02x00:%10d, ",i,cnt);
+ if ((j++ & 3) == 3) s += sprintf(s,"\n");
+ }
+ }
+ if (j & 3) s += sprintf(s,"\n");
+ s += sprintf(s,"Fast reflections by vector:\n");
+ for (i = 0, j = 0; i < 0x80; i++) {
+ if (cnt = fast_reflect_count[i]) {
+ s += sprintf(s,"0x%02x00:%10d, ",i,cnt);
+ if ((j++ & 3) == 3) s += sprintf(s,"\n");
+ }
+ }
+ if (j & 3) s += sprintf(s,"\n");
+ return s - buf;
+}
+
void reflect_interruption(unsigned long ifa, unsigned long isr, unsigned long itiriim, struct pt_regs *regs, unsigned long vector)
{
unsigned long vcpu_get_ipsr_int_state(struct exec_domain *,unsigned long);
regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
// NOTE: nested trap must NOT pass PSCB address
//regs->r31 = (unsigned long) &PSCB(ed);
+ inc_slow_reflect_count(vector);
return;
}
PSCB(ed,interrupt_delivery_enabled) = 0;
PSCB(ed,interrupt_collection_enabled) = 0;
+
+ inc_slow_reflect_count(vector);
}
void foodpi(void) {}
if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs);
else do_ssc(vcpu_get_gr(current,36), regs);
}
- else if (iim == d->breakimm) {
+ else if (iim == d->arch.breakimm) {
if (ia64_hypercall(regs))
vcpu_increment_iip(current);
}
#define starting_rid arch.starting_rid
#define ending_rid arch.ending_rid
#define rid_bits arch.rid_bits
-#define breakimm arch.breakimm
#define xen_vastart arch.xen_vastart
#define xen_vaend arch.xen_vaend
#define shared_info_va arch.shared_info_va
void *regs; /* temporary until find a better way to do privops */
int metaphysical_rr0; // from arch_domain (so is pinned)
int metaphysical_saved_rr0; // from arch_domain (so is pinned)
+ int breakimm; // from arch_domain (so is pinned)
struct mm_struct *active_mm;
struct thread_struct _thread; // this must be last
#ifdef CONFIG_VTI